home *** CD-ROM | disk | FTP | other *** search
Text File | 1989-12-20 | 34.5 KB | 1,356 lines |
- Newsgroups: comp.sources.misc
- subject: v09i085: dtree
- From: djm@abyss.eng.umd.edu (David J. MacKenzie)
- Sender: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)
-
- Posting-number: Volume 9, Issue 85
- Submitted-by: djm@abyss.eng.umd.edu (David J. MacKenzie)
- Archive-name: dtree
-
- This is a new revision of the dtree Unix directory tree printing
- program. Its output has a different, and in my opinion more
- attractive, format from that of the vtree program that appeared in
- comp.sources.unix volume 18.
-
- This version of dtree should work on all Unixes from version 7 onward,
- with some tweaking of the Makefile.
-
- #! /bin/sh
- # This is a shell archive. Remove anything before this line, then unpack
- # it by saving it into a file and typing "sh file". To overwrite existing
- # files, type "sh file -c". You can also feed this as standard input via
- # unshar, or by typing "sh <file", e.g.. If this archive is complete, you
- # will see the following message at the end:
- # "End of shell archive."
- # Contents: README dtree.1 dtree.c getcwd.c Makefile
- # Wrapped by djm@abyss on Wed Dec 20 15:14:15 1989
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- if test -f 'README' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'README'\"
- else
- echo shar: Extracting \"'README'\" \(1014 characters\)
- sed "s/^X//" >'README' <<'END_OF_FILE'
- Xdtree pretty-prints directory structures like this:
- X
- X |-df---------
- X |-ftw--------
- X |
- X | |-bin-src-
- X | |-date----
- X |-gnu--------|-install-
- X | |-lib-----
- X|-src-| |-libc----
- X | |-tput----
- X |-misc-------
- X |-patches----
- X |-printf-----
- X |-qterm------
- X
- XIt was originally written for v7 and 4.1BSD; a version that had been
- Xpartially adapted to the Berkeley Fast File System and portable
- Xdirectory package appeared in mod.sources several years ago, but it
- Xhad several bugs (among the more severe, it always dumps core on some
- Xsystems). This version fixes those and also has improved performance
- Xand more helpful error messages. It also works on System V; for the
- Xbenefit of System V users, I have packaged with dtree Doug Gwyn's free
- Xreimplementation of the getcwd function that doesn't open a pipe to
- X/bin/pwd but determines the current directory directly; this should
- Xhelp performance on those systems.
- END_OF_FILE
- if test 1014 -ne `wc -c <'README'`; then
- echo shar: \"'README'\" unpacked with wrong size!
- fi
- # end of 'README'
- fi
- if test -f 'dtree.1' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'dtree.1'\"
- else
- echo shar: Extracting \"'dtree.1'\" \(2365 characters\)
- sed "s/^X//" >'dtree.1' <<'END_OF_FILE'
- X.TH DTREE 1L
- X.SH NAME
- Xdtree \- display directory tree structures
- X.SH SYNOPSIS
- X.B dtree
- X[
- X.I \-adfgHlnpsvx
- X] [
- X.I \-c linelength
- X] [
- X.BR directory ...
- X]
- X.SH DESCRIPTION
- X.I dtree
- Xdisplays a graphic representation of the directory structure of each given
- X.B directory
- Xand its children. If no directories are specified, the current
- Xdirectory is used.
- XBy default, only
- Xdirectories, not regular files, are shown, and only their
- Xfilenames are given. Various options add additional
- Xinformation to the tree.
- X.SS OPTIONS
- X.TP
- X.I \-a
- XInclude files in the listing (excluding entries beginning with '.').
- X.TP
- X.I \-c linelength
- XMake
- X.I linelength
- Xthe length of each
- Xcolumn of the printout. By default, this is 14.
- XAny entries longer than
- Xthe column length are truncated accordingly, and the last character that
- Xfits into the column is replaced by an asterisk.
- XThis option only has an effect if the
- X.I -v
- Xoption is specified.
- X.TP
- X.I \-d
- XList directories first. For each directory, its subdirectories
- Xwill be listed first, and then all of its other entries.
- X.TP
- X.I \-f
- XList files first. The reverse of
- X.IR \-d .
- X.TP
- X.I \-l
- XLong listing. Display useful information to the right of
- Xeach entry: the name of the file's owner, its size in blocks, and its mode.
- X.TP
- X.I \-g
- XSame as the
- X.I \-l
- Xoption, except that the group name is used instead of
- Xthe owner name. If both the
- X.I \-l
- Xand
- X.I \-g
- Xoptions are used, both the
- Xowner and group will be displayed.
- X.TP
- X.I \-H
- XDisplay a header at the top of the printout that gives the time and
- Xdate that the printout was made and a summary of the type of
- Xinformation contained in the tree.
- X.TP
- X.I \-n
- XNo sort. Entries are listed in the order they are read
- Xfrom the directories.
- X.TP
- X.I \-p
- XInclude entries beginning with '.' (except '.' and '..').
- X.TP
- X.I \-s
- XSimplify the long listing: display the user id, size in blocks, and
- Xoctal mode of the file. This option implies the
- X.I \-l
- Xoption unless the
- X.I \-g
- Xoption is specified.
- X.TP
- X.I \-v
- XDo not let column lengths vary; use the same
- Xwidth for each column of output. The width defaults to 14
- Xbut can be set with the
- X.I \-c
- Xoption.
- X.TP
- X.I \-x
- XDo not cross file systems.
- X.I dtree
- Xwill not cross over to a
- Xsubdirectory if it is on a different file system.
- X.SH AUTHOR
- XDave Borman, Digital Unix Engineering Group
- X.br
- Xdecvax!borman
- X.br
- XOriginally written at St. Olaf College, Northfield, MN.
- END_OF_FILE
- if test 2365 -ne `wc -c <'dtree.1'`; then
- echo shar: \"'dtree.1'\" unpacked with wrong size!
- fi
- # end of 'dtree.1'
- fi
- if test -f 'dtree.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'dtree.c'\"
- else
- echo shar: Extracting \"'dtree.c'\" \(21819 characters\)
- sed "s/^X//" >'dtree.c' <<'END_OF_FILE'
- X/*
- X * DTREE - Print the tree structure of a directory
- X * 4/7/83 name was changed from TREE to DTREE
- X * 9/7/83 mods for 4.1c and 4.2 dirctory structure added
- X *
- X * Dave Borman, Digital Unix Engineering Group
- X * decvax!borman
- X * Originally written at St. Olaf College, Northfield MN.
- X * Copyright (c) 1983 by Dave Borman
- X * All rights reserved
- X * This program may not be sold, but may be distributed
- X * provided this header is included.
- X *
- X * Usage: dtree [-adfgHlnpsvx] [-c line-length] [directory...]
- X * Flags: -a) include non-directory entries in listing
- X * -d) sort tree with directories at the top
- X * -f) sort tree with files at the top
- X * -g) same as l, but use group name instead of user name
- X * -H) display a header at top
- X * -l) print stats with each listing
- X * if both g & l flags are given, both owner and
- X * group will be printed
- X * -n) do not sort the tree
- X * -p) include files starting with a '.' (except "." & "..")
- X * -s) use shorter stats. Implies -l if -g isn't given.
- X * -v) variable length columns off
- X * -x) do not cross mounted file systems.
- X * -c length) set max column length to "length"
- X */
- X
- X /* Modified by Ed Arnold CSU-CS (csu-cs!arnold) 3-5-84
- X *
- X * Allows symbolic links to both directories and individual files.
- X * With a '-l' or '-al' option, links are denoted with a 'l' in front of
- X * file or directory permissions. In all other instances both links to
- X * directories and files are represented just as files are. Contents of
- X * linked directories are not printed due to the possibility of
- X * recursively linked directories.
- X *
- X * Big directory name option added by:
- X * Mike Vevea CSU-CS (csu-cs!vevea) 3-22-84
- X *
- X * Toggle sense of -v (running 4.2), and eliminate some extraneous
- X * print info Mike Meyer Energy Analysts (mwm@ea) 4/17/84
- X *
- X * Fix the exit status to correctly indicate what happened.
- X * Mike Meyer Energy Analysts (mwm@ea) 4/23/84
- X *
- X * Change MAX to INITIAL_ELEM to fix conflict on Suns,
- X * fix incorrect default value for Clength when -v not given,
- X * add -H option to print header with date and description of tree,
- X * remove -b option (useless) and simplify array access,
- X * use getopt to parse options, fix usage message,
- X * use getwd instead of opening a pipe to pwd,
- X * make error messages more informative,
- X * use strncpy instead of sprintf for speed,
- X * move function declarations to top of file,
- X * comment out junk after #else and #endif,
- X * make symbolic link configuring automatic,
- X * check all error returns from malloc and realloc,
- X * add System V/Xenix/Unos compatibility,
- X * remove definition of rindex.
- X * David MacKenzie <djm@eng.umd.edu> 12/20/89
- X */
- X
- X/* Compile-time options:
- X *
- X * STATS leave undefined to remove stats, giving more core space
- X * and thus the ability to tree larger tree structures on PDP 11/70s.
- X *
- X * NEWDIR directory structure a la Berkeley 4.1c or 4.2
- X *
- X * NDIR use <sys/ndir.h> instead of <sys/dir.h>
- X * NEWDIR must be defined as well.
- X *
- X * DIRENT use Posix directory library.
- X * NEWDIR must be defined as well.
- X *
- X * SYSV use getcwd instead of getwd, strrchr instead of rindex.
- X */
- X
- Xstatic char Sccsid[]="@(#)dtree.c 2.3 2/14/84";
- X
- X#ifdef S_IFLNK
- Xstatic char Rcsid[] ="$Header: /mnt/ntape/RCS/dtree.c,v 1.2 84/04/23 10:33:41 root Exp $";
- X#endif /* S_IFLNK */
- X
- X#include <stdio.h>
- X#include <sys/types.h>
- X#include <sys/stat.h>
- X#include <time.h>
- X
- X#ifdef STATS
- X# include <pwd.h>
- X# include <grp.h>
- X#endif /* STATS */
- X
- X#ifdef NEWDIR
- X# if DIRENT
- X# include <dirent.h>
- X# define direct dirent
- X# else
- X# if NDIR
- X# include <sys/ndir.h>
- X# else
- X# include <sys/dir.h>
- X# endif
- X# endif /* DIRENT */
- X#else
- X# include <sys/dir.h>
- X#endif /* NEWDIR */
- X
- X/* default column length when -v is given */
- X#ifdef unos
- X#define DEFCOLWID 30
- X#else
- X#define DEFCOLWID 14
- X#endif
- X
- X#include <sys/param.h> /* for MAXPATHLEN */
- X#ifndef MAXPATHLEN
- X# ifdef LPNMAX /* Xenix from stdio.h */
- X# define MAXPATHLEN (LPNMAX - 1)
- X# else
- X# include <limits.h> /* try somewhere else */
- X# define MAXPATHLEN PATH_MAX
- X# endif
- X#endif
- X
- X#ifndef MAXNAMLEN /* defined with NEWDIR routines */
- X# ifdef LFNMAX /* Xenix again */
- X# define MAXNAMLEN (LFNMAX - 1)
- X# else
- X# define MAXNAMLEN DEFCOLWID
- X# endif
- X#endif
- X
- X#define DEPTH 10 /* maximum depth that dtree will go */
- X#define INITIAL_ELEM 100 /* initial # of elements for list of files */
- X
- X#define FFIRST 2 /* sort files first */
- X#define DFIRST 1 /* sort directories first */
- X#define FAIL -1 /* failure return status of sys calls */
- X#define GREATER 1 /* return value of strcmp if arg1 > arg2 */
- X#define LESSTHAN -1 /* return value of strcmp if arg1 < arg2 */
- X#define SAME 0 /* return value of strcmp if arg1 == arg2 */
- X
- X#ifdef STATS
- Xchar *getmode();
- Xchar *guid();
- Xchar *ggid();
- Xstruct passwd *getpwuid();
- Xstruct group *getgrgid();
- X#endif /* STATS */
- X
- X#ifdef SYSV
- X#define rindex strrchr
- X#endif /* SYSV */
- X
- Xchar *getwd();
- Xchar *malloc();
- Xchar *realloc();
- Xchar *rindex();
- Xint qsort();
- Xlong time();
- X
- Xint compar(); /* comparison routine for qsort */
- Xchar *xmalloc();
- Xchar *xrealloc();
- X
- X#ifdef SYSV
- X#define getwd(buf) getcwd((buf), MAXPATHLEN + 1)
- X#endif /* SYSV */
- X
- Xint Index = 0; /* current element of list[] */
- Xint CLength = 0; /* max length of a column */
- Xint All = 0; /* all != 0; list non-directory entries */
- Xint File_dir = 0; /* flag for how to sort */
- Xint Sort = 1; /* flag to cause sorting of entries */
- Xint Point = 1; /* skip point files if set */
- Xint Header = 0; /* print verbose header */
- Xint Maxes[DEPTH]; /* array keeps track of max length in columns */
- Xint Level = 0; /* counter for how deep we are */
- Xint Device; /* device that we are starting tree on */
- Xint Xdev = 1; /* set to allow crossing of devices */
- Xint Varspaces = 1; /* set to allow compaction of column width */
- X#ifdef STATS
- Xint Gflag = 0; /* set for group stats instead of owner */
- Xint Longflg = 0; /* set for long listing */
- Xint Compact = 0; /* set for shortened long listing */
- X#endif /* STATS */
- Xstruct stat Status;
- X#ifdef S_IFLNK
- Xstruct stat Lstat; /* stat of link, if there is one */
- X#endif /* S_IFLNK */
- X
- Xstruct entry {
- X int next; /* index to next element in list */
- X /* could be a ptr, but realloc() */
- X /* might screw us then */
- X#ifdef STATS
- X off_t e_size; /* size in blocks */
- X unsigned short e_mode; /* file mode */
- X short e_uid; /* uid of owner */
- X short e_gid; /* gid of owner */
- X#endif /* STATS */
- X unsigned short dir : 1; /* entry is a directory */
- X unsigned short last : 1; /* last entry in the dir. */
- X unsigned short dev : 1; /* set if same device as top */
- X unsigned short end : 13; /* index of last subdir entry*/
- X char e_name[MAXNAMLEN + 1]; /* name from directory entry */
- X} *List, *SaveList;
- X
- Xunsigned Size; /* how big of space we've malloced */
- X
- Xchar *Spaces; /* used for output */
- Xchar Buf1[BUFSIZ]; /* buffers for stdio stuff. We don't want */
- X#ifndef NEWDIR
- Xchar Buf2[BUFSIZ]; /* anyone calling malloc, because then */
- X /* realloc() will have to move the whole list */
- X#endif
- X
- Xmain(argc, argv)
- Xchar **argv;
- Xint argc;
- X{
- X extern int optind;
- X extern char *optarg;
- X register int i;
- X char top[MAXPATHLEN + 1]; /* array for treetop name */
- X char home[MAXPATHLEN + 1]; /* starting dir for multiple trees */
- X char *ptr;
- X
- X setbuf(stdout, Buf1);
- X
- X while ((i = getopt (argc, argv,
- X#ifdef STATS
- X "adfgHlnpsvxc:"
- X#else
- X "adfHnpvxc:"
- X#endif /* STATS */
- X )) != EOF) {
- X switch (i) {
- X case 'a':
- X All = 1;
- X break;
- X case 'c':
- X CLength = atoi(optarg);
- X if (CLength > MAXNAMLEN)
- X CLength = MAXNAMLEN;
- X else if (CLength < 1)
- X CLength = DEFCOLWID;
- X break;
- X case 'd':
- X File_dir = DFIRST;
- X break;
- X case 'f':
- X File_dir = FFIRST;
- X break;
- X case 'H':
- X Header = 1;
- X break;
- X case 'n':
- X Sort = 0;
- X break;
- X case 'p':
- X Point = 0;
- X break;
- X case 'v':
- X Varspaces = 0;
- X break;
- X case 'x':
- X Xdev = 0;
- X break;
- X#ifdef STATS
- X case 'g':
- X Gflag = 1;
- X break;
- X case 'l':
- X Longflg = 1;
- X break;
- X case 's':
- X Compact = 1;
- X break;
- X#endif /* STATS */
- X default:
- X fprintf(stderr,
- X#ifdef STATS
- X "Usage: dtree [-adfgHlnpsvx] [-c linelength] [directory ... ]\n"
- X#else /* STATS */
- X "Usage: dtree [-adfHnpvx] [-c linelength] [directory ... ]\n"
- X#endif /* STATS */
- X );
- X exit(FAIL);
- X }
- X }
- X#ifdef STATS
- X if (Compact && !Gflag)
- X Longflg = 1;
- X#endif /* STATS */
- X if (CLength == 0)
- X CLength = Varspaces ? MAXNAMLEN : DEFCOLWID;
- X
- X /* Establish where we are (our home base...) */
- X if (getwd(home) == 0) {
- X fprintf(stderr,
- X "dtree: Cannot get initial directory: %s\n", home);
- X exit(1);
- X }
- X
- X Spaces = xmalloc(MAXNAMLEN+2);
- X for(i = 0; i <= MAXNAMLEN; i++)
- X Spaces[i] = ' ';
- X Spaces[i] = '\0';
- X
- X /* Get initial Storage space */
- X Size = sizeof(struct entry) * INITIAL_ELEM;
- X SaveList = (struct entry *)xmalloc(Size);
- X
- X /* adjust for no specified directory */
- X if (optind == argc)
- X argv[--optind] = ".";
- X
- X if (Header)
- X print_date();
- X
- X /* walk down the rest of the args, treeing them one at at time */
- X for (; optind < argc; optind++) {
- X if (chdir(home) == -1) {
- X fprintf(stderr, "dtree: Cannot change to initial directory ");
- X perror(home);
- X exit(1);
- X }
- X strncpy (top, argv[optind], MAXPATHLEN);
- X
- X if (chdir(top) == FAIL) {
- X fprintf(stderr, "dtree: Cannot change to top directory ");
- X perror(top);
- X continue;
- X } else if (getwd(top) == 0) {
- X fprintf(stderr,"dtree: Cannot get current directory: %s\n", top);
- X continue;
- X }
- X
- X List = SaveList; Index = 0;
- X ptr = rindex(top, '/');
- X
- X if (!ptr || *++ptr == '\0')
- X strncpy(List[Index].e_name, top, MAXNAMLEN);
- X else
- X strncpy(List[Index].e_name, ptr, MAXNAMLEN);
- X
- X if(stat(top, &Status) == FAIL) {
- X fprintf(stderr, "dtree: Cannot stat directory ");
- X perror(top);
- X continue;
- X }
- X Device = Status.st_dev;
- X List[0].dir = 1;
- X List[0].last = 1;
- X List[0].next = 1;
- X#ifdef STATS
- X List[0].e_mode = Status.st_mode;
- X List[0].e_uid = Status.st_uid;
- X List[0].e_gid = Status.st_gid;
- X List[0].e_size = Status.st_size;
- X#endif /* STATS */
- X Index = 1;
- X for (i = 1; i < DEPTH; i++)
- X Maxes[i] = 0;
- X Maxes[0] = stln(List[0].e_name);
- X Level = 1;
- X
- X /* search the tree */
- X List[0].end = t_search(top, &List[0]);
- X
- X if (Index == 1) /* empty tree */
- X List[0].next = 0;
- X
- X if (Header) {
- X if (All)
- X printf("\nDirectory structure and contents of %s\n", top);
- X else
- X printf("\nDirectory structure of %s\n", top);
- X if (Point)
- X printf("(excluding entries that begin with '.')\n");
- X }
- X
- X pt_tree(); /* print the tree */
- X }
- X exit(0) ;
- X}
- X
- X
- Xt_search(dir, addrs)
- Xchar *dir;
- Xstruct entry *addrs;
- X{
- X int bsort; /* index to begin sort */
- X int stmp; /* save temporary index value */
- X struct entry *sstep; /* saved step in list */
- X int nitems; /* # of items in this directory */
- X#ifdef NEWDIR
- X DIR *dirp; /* pointer to directory */
- X#else
- X FILE *dirp;
- X#endif
- X char sub[MAXNAMLEN+1]; /* used for subdirectory names */
- X int i;
- X#ifdef NEWDIR
- X struct direct *dp;
- X#else
- X struct direct dirent;
- X struct direct *dp = &dirent;
- X#endif /* NEWDIR */
- X int n_subs = 0;
- X int tmp = 0;
- X
- X#ifdef NEWDIR
- X dirp = opendir(".");
- X#else
- X dirp = fopen(".", "r");
- X#endif /* NEWDIR */
- X if (dirp == NULL) {
- X fprintf(stderr, "dtree: Cannot open directory ");
- X perror(dir);
- X return(0);
- X }
- X#ifndef NEWDIR
- X setbuf(dirp, Buf2);
- X#endif /* NEWDIR */
- X
- X bsort = Index;
- X sstep = &List[bsort]; /* initialize sstep for for loop later on */
- X nitems = Index;
- X /* get the entries of the directory that we are interested in */
- X#ifndef NEWDIR
- X while (fread((char *)(dp), sizeof(struct direct), 1, dirp) == 1) {
- X#else
- X while ((dp = readdir(dirp)) != NULL) {
- X#endif /* NEWDIR */
- X
- X if (dp->d_ino
- X#ifdef unos
- X == -1
- X#else
- X == 0
- X#endif /* unos */
- X || (strcmp(dp->d_name, ".") == SAME)
- X || (strcmp(dp->d_name, "..") == SAME)
- X || (Point && dp->d_name[0] == '.'))
- X continue;
- X
- X strncpy(sub, dp->d_name, MAXNAMLEN);
- X#ifdef S_IFLNK
- X if (lstat(sub,&Lstat) == FAIL) {
- X fprintf(stderr, "dtree: In directory %s, cannot lstat entry ", dir);
- X perror(sub);
- X continue;
- X }
- X#endif /* S_IFLNK */
- X if (stat(sub, &Status) == FAIL) {
- X fprintf(stderr, "dtree: In directory %s, cannot stat entry ", dir);
- X perror(sub);
- X continue;
- X }
- X#ifdef S_IFLNK
- X if (((Lstat.st_mode & S_IFMT) == S_IFLNK) &&
- X ((Status.st_mode & S_IFMT) == S_IFDIR))
- X List[Index].dir = 0;
- X else if ((((Lstat.st_mode & S_IFMT) == S_IFLNK) &&
- X ((Status.st_mode & S_IFMT) != S_IFDIR)) && (All))
- X List[Index].dir = 0;
- X#endif /* S_IFLNK */
- X else if ((Status.st_mode & S_IFMT) == S_IFDIR)
- X List[Index].dir = 1;
- X else if (All)
- X List[Index].dir = 0;
- X else
- X continue;
- X strncpy(List[Index].e_name, dp->d_name, MAXNAMLEN);
- X List[Index].last = 0;
- X List[Index].end = 0;
- X#ifdef S_IFLNK
- X if ((Lstat.st_mode & S_IFMT) == S_IFLNK) {
- X List[Index].dev = (Device == Lstat.st_dev);
- X List[Index].e_mode = Lstat.st_mode;
- X List[Index].e_uid = Lstat.st_uid;
- X List[Index].e_gid = Lstat.st_gid;
- X List[Index].e_size = Lstat.st_size;
- X }
- X else {
- X#endif /* S_IFLNK */
- X List[Index].dev = (Device == Status.st_dev);
- X#ifdef STATS
- X List[Index].e_mode = Status.st_mode;
- X List[Index].e_uid = Status.st_uid;
- X List[Index].e_gid = Status.st_gid;
- X List[Index].e_size = Status.st_size;
- X#endif /* STATS */
- X#ifdef S_IFLNK
- X }
- X#endif /* S_IFLNK */
- X if (stln(List[Index].e_name) > Maxes[Level])
- X Maxes[Level] = stln(List[Index].e_name);
- X ++Index;
- X if (Index*sizeof(struct entry) >= Size) {
- X Size += 20*sizeof(struct entry);
- X List = (struct entry *)xrealloc((char *)List, Size);
- X }
- X }
- X#ifdef NEWDIR
- X closedir(dirp);
- X#else
- X fclose(dirp);
- X#endif /* NEWDIR */
- X
- X nitems = Index - nitems; /* nitems now contains the # of */
- X /* items in this dir, rather than */
- X /* # total items before this dir */
- X
- X if (Sort)
- X qsort(&List[bsort], nitems, sizeof(struct entry), compar);
- X
- X List[Index-1].last = 1; /* mark last item for this dir */
- X n_subs = nitems;
- X stmp = Index;
- X
- X /* now walk through, and recurse on directory entries */
- X /* sstep was initialized above */
- X
- X for (i = 0; i < nitems; sstep = &List[stmp - nitems+(++i)]) {
- X if (sstep->dir && (Xdev || sstep->dev)) {
- X sstep->next = Index;
- X strncpy(sub, sstep->e_name, MAXNAMLEN);
- X tmp = n_subs;
- X Level++;
- X if (chdir(sub) == FAIL) {
- X fprintf(stderr,
- X "dtree: Cannot change to directory %s/", dir);
- X perror(sub);
- X } else {
- X n_subs += t_search(sub, sstep);
- X if (chdir("..") == FAIL) {
- X fprintf(stderr,
- X "dtree: %s/%s lacks '..' entry\n",dir, sub);
- X exit(1);
- X }
- X }
- X --Level;
- X if (n_subs - tmp <= 0)
- X sstep->next = 0;
- X else
- X --n_subs;
- X }
- X else
- X sstep->next = 0;
- X }
- X addrs->end = (unsigned)n_subs;
- X return(n_subs);
- X}
- X
- X/*
- X * comparison routine for qsort
- X */
- X
- Xcompar(a, b)
- Xstruct entry *a, *b;
- X{
- X if (!File_dir) /* straight alphabetical */
- X return(strncmp(a->e_name, b->e_name, MAXNAMLEN));
- X
- X /* sort alphabetically if both dirs or both not dirs */
- X
- X if ((a->dir && b->dir) || (!a->dir && !b->dir))
- X return(strncmp(a->e_name, b->e_name, MAXNAMLEN));
- X
- X if (File_dir == FFIRST) { /* sort by files first */
- X if (a->dir)
- X return(GREATER);
- X else
- X return(LESSTHAN);
- X }
- X
- X if (a->dir) /* sort by dir first */
- X return(LESSTHAN);
- X else
- X return(GREATER);
- X}
- X
- X
- Xpt_tree()
- X{
- X register int i,j;
- X struct entry *l;
- X struct entry *hdr[DEPTH];
- X int posit[DEPTH]; /* array of positions to print dirs */
- X int con[DEPTH]; /* flags for connecting up tree */
- X char flag = 0; /* flag to leave blank line after dir */
- X struct entry *stack[DEPTH]; /* save positions for changing levels */
- X int top = 0; /* index to top of stack */
- X int count = 1; /* count of line of output */
- X
- X Level = 0; /* initialize Level */
- X
- X /* this loop appends each entry with dashes or spaces, for */
- X /* directories or files respectively */
- X
- X for (i = 0; i < Index; i++) {
- X for (j = 0; j < MAXNAMLEN; j++) {
- X if (!List[i].e_name[j])
- X break;
- X }
- X if (List[i].dir) {
- X for (; j < MAXNAMLEN; j++)
- X List[i].e_name[j] = '-';
- X } else {
- X for (; j < MAXNAMLEN; j++)
- X List[i].e_name[j] = ' ';
- X }
- X }
- X
- X /* adjust the Maxes array according to the flags */
- X
- X for (i = 0; i < DEPTH; i++) {
- X if (Varspaces) {
- X if (Maxes[i] > CLength )
- X Maxes[i] = CLength;
- X } else
- X Maxes[i] = CLength;
- X }
- X
- X /* clear the connective and position flags */
- X
- X for (i = 0; i < DEPTH; i++)
- X con[i] = posit[i] = 0;
- X
- X /* this is the main loop to print the tree structure. */
- X l = &List[0];
- X j = 0;
- X for (;;) {
- X /* directory entry, save it for later printing */
- X if (l->dir != 0 && l->next != 0) {
- X hdr[Level] = l;
- X posit[Level] = count + (l->end + 1)/2 - 1;
- X flag = 1;
- X stack[top++] = l;
- X l = &List[l->next];
- X ++Level;
- X continue;
- X }
- X
- X#ifdef STATS
- X do_it_again:
- X#endif /* STATS */
- X /* print columns up to our entry */
- X for (j = 0; j < (flag ? Level-1 : Level); j++) {
- X if (!flag && posit[j] && posit[j] <= count) {
- X /* time to print it */
- X if (hdr[j]->e_name[CLength-1] != '-')
- X hdr[j]->e_name[CLength-1] = '*';
- X printf("|-%.*s",Maxes[j],hdr[j]->e_name);
- X posit[j] = 0;
- X if (hdr[j]->last != 0)
- X con[j] = 0;
- X else
- X con[j] = 1;
- X#ifdef STATS
- X if (Gflag || Longflg) {
- X if ((i = j+1) <= Level)
- X printf("| %.*s", Maxes[i], Spaces);
- X for (i++; i <= Level; i++) {
- X printf("%c %.*s",
- X (con[i] ? '|' : ' '),
- X Maxes[i], Spaces);
- X }
- X if (!Compact) {
- X printf("%s ", getmode(hdr[j]->e_mode));
- X if (Longflg)
- X printf("%8.8s ",guid(hdr[j]->e_uid));
- X if (Gflag)
- X printf("%8.8s ",ggid(hdr[j]->e_gid));
- X printf("%7ld\n",
- X (hdr[j]->e_size+511L)/512L);
- X } else {
- X printf(" %04o ",hdr[j]->e_mode & 07777);
- X if (Longflg)
- X printf("%5u ", hdr[j]->e_uid);
- X if (Gflag)
- X printf("%5u ", hdr[j]->e_gid);
- X printf("%7ld\n",
- X (hdr[j]->e_size+511L)/512L);
- X }
- X goto do_it_again;
- X }
- X#endif /* STATS */
- X } else
- X printf("%c %.*s", (con[j] ? '|' : ' '),
- X Maxes[j], Spaces);
- X }
- X if (flag) { /* start of directory, so leave a blank line */
- X printf(con[j] ? "|\n" : "\n");
- X flag = 0;
- X continue;
- X } else {
- X /* normal file name, print it out */
- X if (l->e_name[CLength-1] != '-' &&
- X l->e_name[CLength-1] != ' ')
- X l->e_name[CLength-1] = '*';
- X printf("|-%.*s",Maxes[Level],l->e_name);
- X if (l->last) {
- X con[j] = 0;
- X } else {
- X con[j] = 1;
- X }
- X#ifdef STATS
- X if (Gflag || Longflg) {
- X if (Compact) {
- X printf(" %04o ", l->e_mode & 07777);
- X if (Longflg)
- X printf("%5u ", l->e_uid);
- X if (Gflag)
- X printf("%5u ", l->e_gid);
- X printf("%7ld",
- X (l->e_size+511L)/512L);
- X } else {
- X printf("%s ", getmode(l->e_mode));
- X if (Longflg)
- X printf("%8.8s ",guid(l->e_uid));
- X if (Gflag)
- X printf("%8.8s ",ggid(l->e_gid));
- X printf("%7ld",
- X (l->e_size+511L)/512L);
- X }
- X }
- X#endif /* STATS */
- X }
- X printf("\n");
- X
- X if (l->last) {
- X /* walk back up */
- X while (l->last) {
- X --Level;
- X if (--top <= 0)
- X return;
- X l = stack[top];
- X }
- X }
- X l = &l[1];
- X ++count;
- X }
- X}
- X
- X#ifdef STATS
- X
- Xchar *
- Xguid(uid)
- Xshort uid;
- X{
- X static char tb[10];
- X struct passwd *pswd;
- X
- X pswd = getpwuid(uid);
- X if (pswd == NULL)
- X sprintf(tb,"%u", uid);
- X else
- X sprintf(tb, "%8s", pswd->pw_name);
- X return(tb);
- X}
- X
- Xchar *
- Xggid(gid)
- Xshort gid;
- X{
- X static char tb[10];
- X struct group *grp;
- X
- X grp = getgrgid(gid);
- X if (grp == NULL)
- X sprintf(tb,"%u", gid);
- X else
- X sprintf(tb, "%8s", grp->gr_name);
- X return(tb);
- X}
- X
- X/* take the mode and make it into a nice character string */
- X
- Xchar *
- Xgetmode(p_mode)
- Xunsigned short p_mode;
- X{
- X static char a_mode[16];
- X register int i = 0, j = 0;
- X
- X a_mode[j++] = ' ';
- X
- X switch (p_mode & S_IFMT) {
- X#ifdef S_IFLNK
- X case S_IFLNK:
- X a_mode[j++] = 'l';
- X break;
- X#endif /* S_IFLNK */
- X case S_IFDIR:
- X a_mode[j++] = 'd';
- X break;
- X#ifdef S_IFMPC /* defined in stat.h if you have MPX files */
- X case S_IFMPC:
- X a_mode[j-1] = 'm';
- X /* FALL THROUGH */
- X#endif /* S_IFMPC */
- X case S_IFCHR:
- X a_mode[j++] = 'c';
- X break;
- X#ifdef S_IFMPB /* defined in stat.h if you have MPX files */
- X case S_IFMPB:
- X a_mode[j-1] = 'm';
- X /* FALL THROUGH */
- X#endif /* S_IFMPB */
- X case S_IFBLK:
- X a_mode[j++] = 'b';
- X break;
- X case S_IFREG:
- X default:
- X a_mode[j++] = (p_mode & S_ISVTX) ? 't' : ' ';
- X break;
- X }
- X a_mode[j++] = ' ';
- X for( i = 0;i<3;i++ ) {
- X a_mode[j++] = (p_mode<<(3*i) & S_IREAD) ? 'r' : '-';
- X a_mode[j++] = (p_mode<<(3*i) & S_IWRITE) ? 'w' : '-';
- X a_mode[j++] = (i<2 && (p_mode<<i & S_ISUID)) ? 's' :
- X ((p_mode<<(3*i) & S_IEXEC ) ? 'x' : '-');
- X a_mode[j++] = ' ';
- X }
- X a_mode[j] = '\0';
- X return(a_mode);
- X}
- X#endif
- X
- X/* like strlen, but returns length up to MAXNAMLEN-1 */
- Xstln(st)
- Xregister char *st;
- X{
- X register int t;
- X
- X for (t=0; t<MAXNAMLEN-1; ++t)
- X if (!st[t])
- X return (++t);
- X return (++t);
- X}
- X
- Xprint_date()
- X{
- X long now;
- X
- X time(&now);
- X printf ("%s", ctime(&now));
- X}
- X
- Xvoid
- Xmemory_out()
- X{
- X fprintf(stderr, "dtree: Virtual memory exhausted\n");
- X exit(1);
- X}
- X
- X/* Allocate `size' bytes of memory dynamically, with error checking. */
- X
- Xchar *
- Xxmalloc (size)
- Xunsigned size;
- X{
- X char *ptr;
- X
- X ptr = malloc (size);
- X if (ptr == 0 && size != 0)
- X memory_out ();
- X return ptr;
- X}
- X
- X/* Change the size of an allocated block of memory `ptr' to `size' bytes,
- X with error checking.
- X If `ptr' is NULL, run xmalloc.
- X If `size' is 0, run free and return NULL. */
- X
- Xchar *
- Xxrealloc (ptr, size)
- Xchar *ptr;
- Xunsigned size;
- X{
- X if (ptr == 0)
- X return xmalloc (size);
- X if (size == 0) {
- X free (ptr);
- X return 0;
- X }
- X ptr = realloc (ptr, size);
- X if (ptr == 0 && size != 0)
- X memory_out ();
- X return ptr;
- X}
- END_OF_FILE
- if test 21819 -ne `wc -c <'dtree.c'`; then
- echo shar: \"'dtree.c'\" unpacked with wrong size!
- fi
- # end of 'dtree.c'
- fi
- if test -f 'getcwd.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'getcwd.c'\"
- else
- echo shar: Extracting \"'getcwd.c'\" \(5247 characters\)
- sed "s/^X//" >'getcwd.c' <<'END_OF_FILE'
- X/*
- X getcwd -- get current working directory name (POSIX and SVID compatible)
- X
- X last edit: 21-Sep-1987 D A Gwyn
- X
- X This public-domain getcwd() routine can be used to replace the UNIX
- X System V library routine (which uses popen() to capture the output of
- X the "pwd" command). Once that is done, "pwd" can be reimplemented as
- X just puts(getcwd()).
- X
- X This implementation depends on every directory having entries for
- X "." and "..". It also depends on the internals of the <dirent.h>
- X data structures to some degree.
- X
- X I considered using chdir() to ascend the hierarchy, followed by a
- X final chdir() to the path being returned by getcwd() to restore the
- X location, but decided that error recovery was too difficult that way.
- X The algorithm I settled on was inspired by my rewrite of the "pwd"
- X utility, combined with the dotdots[] array trick from the SVR2 shell.
- X*/
- X#include <sys/types.h>
- X#include <sys/stat.h>
- X#include <string.h>
- X#include <dirent.h>
- X#include <errno.h>
- X
- Xtypedef char *pointer; /* (void *) if you have it */
- X
- Xextern void free();
- Xextern pointer malloc();
- Xextern int fstat(), stat();
- X
- Xextern int errno; /* normally done by <errno.h> */
- X
- X#ifndef NULL
- X#define NULL 0 /* amorphous null pointer constant */
- X#endif
- X
- X#ifndef NAME_MAX
- X#define NAME_MAX 255 /* maximum directory entry size */
- X#endif
- X
- Xchar *
- Xgetcwd( buf, size ) /* returns pointer to CWD pathname */
- X char *buf; /* where to put name (NULL to malloc) */
- X int size; /* size of buf[] or malloc()ed memory */
- X {
- X static char dotdots[] =
- X"../../../../../../../../../../../../../../../../../../../../../../../../../..";
- X char *dotdot; /* -> dotdots[.], right to left */
- X DIR *dirp; /* -> parent directory stream */
- X struct dirent *dir; /* -> directory entry */
- X struct stat stat1, stat2; /* info from stat() */
- X struct stat *d = &stat1; /* -> info about "." */
- X struct stat *dd = &stat2; /* -> info about ".." */
- X register char *buffer; /* local copy of buf, or malloc()ed */
- X char *bufend; /* -> buffer[size] */
- X register char *endp; /* -> end of reversed string */
- X register char *dname; /* entry name ("" for root) */
- X int serrno = errno; /* save entry errno */
- X
- X if ( size == 0 )
- X {
- X errno = EINVAL; /* invalid argument */
- X return NULL;
- X }
- X
- X if ( (buffer = buf) == NULL /* wants us to malloc() the string */
- X && (buffer = (char *)malloc( (unsigned)size )) == NULL
- X ) {
- X errno = ENOMEM; /* cannot malloc() specified size */
- X return NULL;
- X }
- X
- X if ( stat( ".", dd ) != 0 ) /* prime the pump */
- X goto error; /* errno already set */
- X
- X endp = buffer; /* initially, empty string */
- X bufend = &buffer[size];
- X
- X for ( dotdot = &dotdots[sizeof(dotdots)]; dotdot != dotdots; )
- X {
- X dotdot -= 3; /* include one more "/.." section */
- X /* (first time is actually "..") */
- X
- X /* swap stat() info buffers */
- X {
- X register struct stat *temp = d;
- X
- X d = dd; /* new current dir is old parent dir */
- X dd = temp;
- X }
- X
- X if ( (dirp = opendir( dotdot )) == NULL ) /* new parent */
- X goto error; /* errno already set */
- X
- X if ( fstat( dirp->dd_fd, dd ) != 0 )
- X {
- X serrno = errno; /* set by fstat() */
- X (void)closedir( dirp );
- X errno = serrno; /* in case closedir() clobbered it */
- X goto error;
- X }
- X
- X if ( d->st_dev == dd->st_dev )
- X { /* not crossing a mount point */
- X if ( d->st_ino == dd->st_ino )
- X { /* root directory */
- X dname = "";
- X goto append;
- X }
- X
- X do
- X if ( (dir = readdir( dirp )) == NULL )
- X {
- X (void)closedir( dirp );
- X errno = ENOENT; /* missing entry */
- X goto error;
- X }
- X while ( dir->d_ino != d->st_ino );
- X }
- X else { /* crossing a mount point */
- X struct stat t; /* info re. test entry */
- X char name[sizeof(dotdots) + 1 + NAME_MAX];
- X
- X (void)strcpy( name, dotdot );
- X dname = &name[strlen( name )];
- X *dname++ = '/';
- X
- X do {
- X if ( (dir = readdir( dirp )) == NULL )
- X {
- X (void)closedir( dirp );
- X errno = ENOENT; /* missing entry */
- X goto error;
- X }
- X
- X (void)strcpy( dname, dir->d_name );
- X /* must fit if NAME_MAX is not a lie */
- X }
- X while ( stat( name, &t ) != 0
- X || t.st_ino != d->st_ino
- X || t.st_dev != d->st_dev
- X );
- X }
- X
- X dname = dir->d_name;
- X
- X /* append "/" and reversed dname string onto buffer */
- X append:
- X if ( endp != buffer /* avoid trailing / in final name */
- X || dname[0] == '\0' /* but allow "/" when CWD is root */
- X )
- X *endp++ = '/';
- X
- X {
- X register char *app; /* traverses dname string */
- X
- X for ( app = dname; *app != '\0'; ++app )
- X ;
- X
- X if ( app - dname >= bufend - endp )
- X {
- X (void)closedir( dirp );
- X errno = ERANGE; /* won't fit allotted space */
- X goto error;
- X }
- X
- X while ( app != dname )
- X *endp++ = *--app;
- X }
- X
- X (void)closedir( dirp );
- X
- X if ( dname[0] == '\0' ) /* reached root; wrap it up */
- X {
- X register char *startp; /* -> buffer[.] */
- X
- X *endp = '\0'; /* plant null terminator */
- X
- X /* straighten out reversed pathname string */
- X for ( startp = buffer; --endp > startp; ++startp )
- X {
- X char temp = *endp;
- X
- X *endp = *startp;
- X *startp = temp;
- X }
- X
- X errno = serrno; /* restore entry errno */
- X return buffer;
- X }
- X }
- X
- X errno = ENOMEM; /* actually, algorithm failure */
- X
- X error:
- X if ( buf == NULL )
- X free( (pointer)buffer );
- X
- X return NULL;
- X }
- X
- END_OF_FILE
- if test 5247 -ne `wc -c <'getcwd.c'`; then
- echo shar: \"'getcwd.c'\" unpacked with wrong size!
- fi
- # end of 'getcwd.c'
- fi
- if test -f 'Makefile' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'Makefile'\"
- else
- echo shar: Extracting \"'Makefile'\" \(728 characters\)
- sed "s/^X//" >'Makefile' <<'END_OF_FILE'
- X# Makefile for dtree
- X
- X# Things that might go in DEFS:
- X# -DSTATS -DNEWDIR -DDIRENT -DNDIR -DSYSV
- XDEFS = -DSTATS -DNEWDIR -DDIRENT
- XCFLAGS = $(DEFS) -O
- XLDFLAGS = -s
- XLIBS = # For Xenix use -lx with -DNDIR
- X
- XBINDIR = /usr/local/bin
- XMANDIR = /usr/local/man/man1
- X
- XOBJECTS = dtree.o #getcwd.o
- X
- XARCH_FILES = README dtree.1 dtree.c getcwd.c Makefile
- X
- Xall: dtree
- X
- Xdtree: $(OBJECTS)
- X $(CC) -o dtree $(LDFLAGS) $(OBJECTS) $(LIBS)
- X
- Xinstall: dtree dtree.1
- X cp dtree $(BINDIR)
- X cp dtree.1 $(MANDIR)
- X
- Xlint: dtree.c
- X lint $(DEFS) dtree.c
- X
- Xshar: $(ARCH_FILES)
- X shar $(ARCH_FILES) > dtree.shar
- X
- Xdist: dtree.tar.Z
- X
- Xtar: dtree.tar.Z
- X
- Xdtree.tar.Z: $(ARCH_FILES)
- X tar cf - $(ARCH_FILES) | compress > dtree.tar.Z
- X
- Xclean:
- X rm -f dtree *.o core tags a.out
- END_OF_FILE
- if test 728 -ne `wc -c <'Makefile'`; then
- echo shar: \"'Makefile'\" unpacked with wrong size!
- fi
- # end of 'Makefile'
- fi
- echo shar: End of shell archive.
- exit 0
-
-